package com.xunwulian.web.bean;

import com.xunwulian.base.exception.PayException;
import com.xunwulian.base.param.WeixinParam;
import com.xunwulian.base.util.HttpUtil;
import com.xunwulian.base.util.StringUtil;
import com.xunwulian.web.util.WeiXinUtil;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * 创建的订单，向微信官方申请订单的二维码时需要
 */
public class WeixinEntity implements Serializable {
    // (必填) String(32) 公众账号ID <有默认值>
    public String appid;

    // (必填) String(32) 商户号 <有默认值>
    public String mch_id;

    // (必填) String(32) 随机字符串 <有默认值>
    public String nonce_str;

    // (必填) String(32) 商品描述
    public String body;

    // (必填) String(32) 签名
    public String sign;

    // (必填) String(32) 商户订单号 <有默认值>
    public String out_trade_no;

    // (必填) Int 标价金额
    public int total_fee;

    // (必填) String(16) 终端ip <有默认值>
    public String spbill_create_ip;

    // (必填) String(256) 通知地址
    public String notify_url;

    // (必填) String(16) 交易类型 <有默认值>
    public String trade_type;

    // 私钥 <有默认值>
    public String privateKey;

    // (可选) String(32) 商品id
    public String product_id;

    // (可选) String(6000) 商品详情
    public String detail;

    // (可选) String(127) 附加数据
    public String attach;

    // (可选) String(14) 交易起始时间
    public String time_start;

    // (可选) String(14) 交易失效时间
    public String time_expire;

    public String code_url;

    /**
     * 默认的构造函数，填入7项默认值，还至少需要填写3项必填内容
     */
    public WeixinEntity() {
        this.appid = WeixinParam.APPID;
        this.mch_id = WeixinParam.MCH_ID;
        this.privateKey = WeixinParam.PRIVATE_KEY;
        this.trade_type = WeixinParam.TRADE_TYPE;
        this.nonce_str = StringUtil.createIdentity(32);
        this.out_trade_no = StringUtil.createIdentity(32);
        this.spbill_create_ip = HttpUtil.localIp();
    }

    /**
     * 调用默认构造器，然后传入的3个参数填充剩余必要的3项参数
     *
     * @param body       商品描述
     * @param total_fee  总金额，单位为分
     * @param notify_url 回调的地址
     */
    public WeixinEntity(String body, int total_fee, String notify_url) {
        this();

        this.body = body;
        this.total_fee = total_fee;
        this.notify_url = notify_url;
    }

    /**
     * 生成参数Map
     *
     * @return 返回生成的map
     * @throws PayException 自定义的异常类型，其实只是简单的打印异常内容
     */
    public Map<String, String> generateParamMap() throws PayException {
        Map<String, String> paramMap = new HashMap();

        // 检查appid
        if (StringUtils.isBlank(appid) || appid.length() > 32) {
            throw new PayException("appid 格式不正确...");
        } else {
            paramMap.put("appid", appid);
        }

        // 检查mch_id
        if (StringUtils.isBlank(mch_id) || mch_id.length() > 32) {
            throw new PayException("mch_id 格式不正确...");
        } else {
            paramMap.put("mch_id", mch_id);
        }

        // 检查nonce_str
        if (StringUtils.isBlank(nonce_str) || nonce_str.length() > 32) {
            throw new PayException("nonce_str 格式不正确...");
        } else {
            paramMap.put("nonce_str", nonce_str);
        }

        // 检查body
        if (StringUtils.isBlank(body) || body.length() > 32) {
            throw new PayException("body 格式不正确...");
        } else {
            paramMap.put("body", body);
        }

        // 检查detail
        if (StringUtils.isNotBlank(detail)) {
            if (detail.length() > 6000) {
                throw new PayException("detail 格式不正确...");
            } else {
                paramMap.put("detail", detail);
            }
        }

        // 检查attache
        if (StringUtils.isNotBlank(attach)) {
            if (attach.length() > 127) {
                throw new PayException("attach 格式不正确...");
            } else {
                paramMap.put("attach", attach);
            }
        }

        // 检查out_trade_no
        if (StringUtils.isBlank(out_trade_no) || out_trade_no.length() > 32) {
            throw new PayException("out_trade_no 格式不正确...");
        } else {
            paramMap.put("out_trade_no", out_trade_no);
        }

        // 检查total_fee
        if (total_fee < 1) {
            throw new PayException("total_fee 格式不正确...");
        } else {
            paramMap.put("total_fee", String.valueOf(total_fee));
        }

        // 检查spbill_create_ip
        if (StringUtils.isBlank(spbill_create_ip) || spbill_create_ip.length() > 16) {
            throw new PayException("spbill_create_ip 格式不正确...");
        } else {
            paramMap.put("spbill_create_ip", spbill_create_ip);
        }

        // TODO time_start,time_expire暂且不做处理

        // 检查notify_url
        if (StringUtils.isBlank(notify_url) || notify_url.length() > 256) {
            throw new PayException("notify_url 格式不正确...");
        } else {
            paramMap.put("notify_url", notify_url);
        }

        // TODO 设置trade_type，这里以后再做处理
        paramMap.put("trade_type", trade_type);

        // 检查product_id
        if (StringUtils.isNotBlank(product_id)) {
            if (attach.length() > 32) {
                throw new PayException("product_id 格式不正确...");
            } else {
                paramMap.put("product_id", product_id);
            }
        }

        // 设置sign
        sign = WeiXinUtil.signByMD5(paramMap, StringUtil.orderByAscii(paramMap.keySet()), privateKey);
        paramMap.put("sign", sign);

        return paramMap;
    }

    @Override
    public String toString() {
        StringBuilder inf = new StringBuilder();
        inf.append("[公众账号=" + appid + "]\n");
        inf.append("[商户号=" + mch_id + "]\n");
        inf.append("[随机数=" + nonce_str + "]\n");
        inf.append("[简要描述=" + body + "]\n");
        inf.append("[签名=" + sign + "]\n");
        inf.append("[详情=" + detail + "]\n");
        inf.append("[附加数据=" + attach + "]\n");
        inf.append("[商户订单号=" + out_trade_no + "]\n");
        inf.append("[金额=" + (total_fee / 100.0) + "￥]\n");
        inf.append("[IP=" + spbill_create_ip + "]\n");
        inf.append("[起始时间=" + time_start + "]\n");
        inf.append("[失效时间=" + time_expire + "]\n");
        inf.append("[回调地址=" + notify_url + "]\n");
        inf.append("[交易类型=" + trade_type + "]\n");
        inf.append("[商品标识=" + product_id + "]\n");
        inf.append("[秘钥=" + privateKey + "]\n");
        return inf.toString();
    }
}
